package com.unicom.office.impl;

import com.unicom.office.builder.ExcelBuilder;
import com.unicom.office.config.OfficeConfig;
import com.unicom.office.node.TextRangeNode;
import com.unicom.office.runtime.OfficeRuntime;
import com.unicom.office.unit.*;
import org.apache.poi.ss.formula.ConditionalFormattingEvaluator;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;

import java.awt.Color;
import java.io.FileOutputStream;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

public class XlsxBuilder extends ExcelBuilder {
    public XlsxBuilder(){
        super(null, null);
    }

    public XlsxBuilder(OfficeConfig config, OfficeRuntime runtime) {
        super(config, runtime);
    }

    protected Object buildWorkbook(WorkbookUnit unit) {
        XSSFWorkbook workbook = new XSSFWorkbook();

        for (OfficeUnit child : unit.getChildren()) {
            build2(child, workbook);
        }

        return workbook;
    }

    protected Object buildWorksheet(WorksheetUnit unit, Object parent) {
        Sheet sourceSheet = (Sheet) unit.getSource();
        Workbook workbook = (Workbook) parent;
        Sheet sheet = workbook.createSheet(sourceSheet.getSheetName());

        // 列宽度怎么改？
        int num = getColumnNum(sourceSheet);
        for(int i = 0; i <= num; i++){
            int columnWidth = sourceSheet.getColumnWidth(i);
            sheet.setColumnWidth(i, columnWidth);
            sheet.setColumnHidden(i, sourceSheet.isColumnHidden(i));
            if(sourceSheet.isColumnBroken(i)){
                sheet.setColumnBreak(i);
            }
        }

        for (OfficeUnit child : unit.getChildren()) {
            build2(child, sheet);
        }

        for (OfficeUnit child : unit.getTextboxs()) {
            build2(child, sheet);
        }

        return sheet;
    }

    private int getColumnNum(Sheet sheet){
        int num = 0;
        Iterator<Row> rowIterator = sheet.rowIterator();
        while (rowIterator.hasNext()){
            Row next = rowIterator.next();
            short lastCellNum = next.getLastCellNum();
            if(lastCellNum > num){
                num = lastCellNum;
            }
        }
        return num;
    }

    protected Object buildRow(RowUnit unit, Object parent) {
        Sheet sheet = (Sheet) parent;
        Row row = sheet.createRow(sheet.getLastRowNum() + 1);
        if(unit.getSource() == null) {
            return row;
        }
        Row sourceRow = (Row)unit.getSource();

        // 设置样式
        row.setHeight(sourceRow.getHeight());

        for (OfficeUnit child : unit.getChildren()) {
            build2(child, row);
        }

        return row;
    }

    protected Object buildCell(CellUnit unit, Object parent) {
        XSSFRow row = (XSSFRow) parent;
        XSSFCell sourceCell = (XSSFCell)unit.getSource();
        short lastCellNum = row.getLastCellNum();
        if(lastCellNum == -1) {
            lastCellNum = 0;
        }
        XSSFCell cell = row.createCell(lastCellNum);
        if(sourceCell != null){
            copyCellFrom(cell, sourceCell, new CellCopyPolicy(), unit);
        }

        return cell;
    }

    public void copyCellFrom(Cell cell, Cell srcCell, CellCopyPolicy policy, CellUnit unit) {
        if (policy.isCopyCellValue()) {
            if (srcCell != null) {
                CellType copyCellType = srcCell.getCellType();
                if (copyCellType == CellType.FORMULA && !policy.isCopyCellFormula()) {
                    copyCellType = srcCell.getCachedFormulaResultType();
                }

                if(unit.isJustResource()){
                    switch(copyCellType) {
                        case NUMERIC:
                            if (DateUtil.isCellDateFormatted(srcCell)) {
                                cell.setCellValue(srcCell.getDateCellValue());
                            } else {
                                cell.setCellValue(srcCell.getNumericCellValue());
                            }
                            break;
                        case STRING:
                            cell.setCellValue(srcCell.getStringCellValue());
                            break;
                        case FORMULA:
                            cell.setCellFormula(srcCell.getCellFormula());
                            break;
                        case BLANK:
                            cell.setBlank();
                            break;
                        case BOOLEAN:
                            cell.setCellValue(srcCell.getBooleanCellValue());
                            break;
                        case ERROR:
                            cell.setCellErrorValue(srcCell.getErrorCellValue());
                            break;
                        default:
                            throw new IllegalArgumentException("Invalid cell type " + srcCell.getCellType());
                    }
                }else {
                    switch(copyCellType) {
                        case NUMERIC:
                            String temp = srcCell.getStringCellValue();
                            srcCell.setCellValue(Double.parseDouble(unit.getText()));
                            if (DateUtil.isCellDateFormatted(srcCell)) {
                                cell.setCellValue(srcCell.getDateCellValue());
                            } else {
                                cell.setCellValue(srcCell.getNumericCellValue());
                            }
                            srcCell.setCellValue(temp);
                            break;
                        case STRING:
                            // 设置文本
                            if(unit.isNumeric()) {
                                String temp1 = srcCell.getStringCellValue();
                                srcCell.setCellValue(Double.parseDouble(unit.getText()));
                                if (DateUtil.isCellDateFormatted(srcCell)) {
                                    cell.setCellValue(srcCell.getDateCellValue());
                                } else {
                                    cell.setCellValue(srcCell.getNumericCellValue());
                                }
                                srcCell.setCellValue(temp1);
                            }else {
                                for (OfficeUnit paragraph : unit.getChildren()) {
                                    cell.setCellValue(buildRichText((ParagraphUnit) paragraph));
                                }
                            }
                            break;
                        case FORMULA:
                            cell.setCellFormula(srcCell.getCellFormula());
                            break;
                        case BLANK:
                            cell.setBlank();
                            break;
                        case BOOLEAN:
                            cell.setCellValue(srcCell.getBooleanCellValue());
                            break;
                        case ERROR:
                            cell.setCellErrorValue(srcCell.getErrorCellValue());
                            break;
                        default:
                            throw new IllegalArgumentException("Invalid cell type " + srcCell.getCellType());
                    }
                }
            } else {
                cell.setBlank();
            }
        }

        if (policy.isCopyCellStyle()) {
            CellStyle cStyle = cell.getSheet().getWorkbook().createCellStyle();
            try{
                // 这里try一下，错误如下，暂时没有解决
                //  at org.apache.poi.xssf.model.StylesTable.getNumberFormatId(StylesTable.java:273)
                //	at org.apache.poi.xssf.model.StylesTable.putNumberFormat(StylesTable.java:295)
                //	at org.apache.poi.xssf.usermodel.XSSFDataFormat.getFormat(XSSFDataFormat.java:52)
                //	at org.apache.poi.xssf.usermodel.XSSFCellStyle.cloneStyleFrom(XSSFCellStyle.java:185)
                //	at com.unicom.office.impl.XlsxBuilder.copyCellFrom(XlsxBuilder.java:170)
                cStyle.cloneStyleFrom(srcCell.getCellStyle());
                cell.setCellStyle(cStyle);
            }catch (Exception ex){
                System.out.println(srcCell.getCellType().name());
            }
        }

        Hyperlink srcHyperlink = srcCell == null ? null : srcCell.getHyperlink();
        if (policy.isMergeHyperlink()) {
            if (srcHyperlink != null) {
                cell.setHyperlink(new XSSFHyperlink(srcHyperlink));
            }
        } else if (policy.isCopyHyperlink()) {
            cell.setHyperlink(srcHyperlink == null ? null : new XSSFHyperlink(srcHyperlink));
        }

        if(policy.isCopyMergedRegions()){
            List<CellRangeAddress> mergedRegions = srcCell.getSheet().getMergedRegions();
            for (CellRangeAddress mergedRegion : mergedRegions) {
                if(mergedRegion.getFirstRow() == srcCell.getRowIndex()
                        && mergedRegion.getFirstColumn() == srcCell.getColumnIndex()){
                    int rowGap = cell.getRowIndex() - srcCell.getRowIndex();
                    int columnGap = cell.getColumnIndex() - srcCell.getColumnIndex();
                    mergedRegion = mergedRegion.copy();
                    mergedRegion.setFirstRow(mergedRegion.getFirstRow() + rowGap);
                    mergedRegion.setLastRow(mergedRegion.getLastRow() + rowGap);
                    mergedRegion.setFirstColumn(mergedRegion.getFirstColumn() + columnGap);
                    mergedRegion.setLastColumn(mergedRegion.getLastColumn() + columnGap);
                    cell.getSheet().addMergedRegion(mergedRegion.copy());
                    break;
                }
            }
        }
    }

    private RichTextString buildRichText(ParagraphUnit paragraphUnit) {
        XSSFRichTextString richTextString = new XSSFRichTextString();
        String str = "";
        for (OfficeUnit child : paragraphUnit.getChildren()) {
            if(child.getSource() != null) {
                richTextString.append(str);
                str = "";
                richTextString.append(child.toString(), (XSSFFont)child.getSource());
            }else {
                str += child.toString();
            }
        }
        if(str.length() > 0) {
            richTextString.append(str);
        }

        return richTextString;
    }

    protected Object buildParagraph(ParagraphUnit unit, Object parent) {
        XSSFTextBox textbox = (XSSFTextBox) parent;
        XSSFTextParagraph paragraph = textbox.addNewTextParagraph();

        // 将文本添加到段落
        for (OfficeUnit child : unit.getChildren()) {
            if(child instanceof TextRangeUnit) {
                TextRangeUnit textRangeUnit = (TextRangeUnit)child;
                XSSFTextRun textRun = paragraph.addNewTextRun();
                textRun.setText(textRangeUnit.getText());
                if(textRangeUnit.getTextStype() != null){
                    textRun.setBold(textRangeUnit.getTextStype().isBold());
                    Color color = textRangeUnit.getTextStype().getColor();
                    if(color != null) {
                        textRun.setFontColor(color);
                    }
                }
            }
        }

        return paragraph;
    }

    protected Object buildTextbox(TextboxUnit unit, Object parent) {
        XSSFSheet sheet = (XSSFSheet) parent;
        XSSFSimpleShape sourceTextbox = (XSSFSimpleShape)unit.getSource();

        XSSFDrawing drawingPatriarch = sheet.getDrawingPatriarch();
        if(drawingPatriarch == null) {
            drawingPatriarch = sheet.createDrawingPatriarch();
        }
        XSSFSimpleShape textbox = sheet.getDrawingPatriarch().createTextbox((XSSFClientAnchor) sourceTextbox.getAnchor());
        // 设置文本框背景色和描边等，但是获取不到啊

        for (OfficeUnit child : unit.getChildren()) {
            build2(child, textbox);
        }

        return textbox;
    }

    protected Object buildTextrange(TextRangeUnit unit, Object parent) {
        return null;
    }

    protected Object buildPicture(PictureUnit unit, Object parent) {
        return null;
    }

    public void writeFile(Object result, String targetPath) {
        if(!(result instanceof Workbook)) {
            throw new RuntimeException("不能输出文件");
        }

        Workbook wb = (Workbook)result;
        try {
            FileOutputStream file = new FileOutputStream(targetPath);
            wb.write(file);
            file.close();
        }catch(Exception ex){
            throw new RuntimeException(ex.getMessage());
        }
    }
}
